﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ARR.Entities;
using System.Collections.ObjectModel;
using DDF.Entity;
using ARR.UI.CategoriesService;
using ARR.UI.CountryService;
using ARR.UI.AttributesService;
using ARR.UI.ArticlesService;
using ARR.UI.UnitsOfMeasureService;

namespace ARR.UI.Models
{
    public interface IArticleMasterModel : IModelBase
    {
        List<Article> Articles { get; set; }

        List<AttributeType> AttributeTypes { get; set; }

        List<Comment> Comments { get; set; }

        List<RangeReview> RangeReviews { get; set; }

        List<Category> Categories { get; set; }

        List<PlanogramLocation> PlanogramLocations { get; set; }

        List<UnitOfMeasureConvertion> UomConvertions { get; set; }

        List<Category> SubCategories { get; set; }

        void DeleteArticles(List<Article> SelectedArticles);

        void Save();

        void LoadArticles(int? categoryId);

        void LoadSubCategories(int categoryId);

        void SplitArticle(Article SelectedArticle, List<Article> list);

        List<Article> SearchArticles(string criteria);
    }


    public class ArticleMasterModel : ModelBase, IArticleMasterModel
    {
        public ArticleMasterModel()
        {
            Articles = new List<Article>();
            RangeReviews = new List<RangeReview>();
            Categories = new List<Category>();
            SubCategories = new List<Category>();
            AttributeTypes = new List<AttributeType>();
            Comments = new List<Comment>();
            UomConvertions = new List<UnitOfMeasureConvertion>();
            PlanogramLocations = new List<PlanogramLocation>();

            LoadAttributeTypes();
            LoadRangeReviews();
            LoadCategories();
            LoadComments();
            LoadUomConvertions();
            LoadPlanogramLocations();
        }

        public List<Article> Articles { get; set; }

        public List<AttributeType> AttributeTypes { get; set; }

        public List<RangeReview> RangeReviews { get; set; }

        public List<Category> Categories { get; set; }

        public List<Category> SubCategories { get; set; }

        public List<Comment> Comments { get; set; }

        public List<UnitOfMeasureConvertion> UomConvertions { get; set; }

        public List<PlanogramLocation> PlanogramLocations { get; set; }

        public void LoadPlanogramLocations()
        {
            SpacesService.SpacesServiceClient service = new SpacesService.SpacesServiceClient();

            try
            {
                PlanogramLocations = service.GetAllPlanogramLocations();
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }

        public void DeleteArticles(List<Article> SelectedArticles)
        {
            //TODO: Implementar el delelete, consultar si hay que tener en cuenta algo en especial para eliminar articulos.
            throw new NotImplementedException();
        }

        public List<Article> SearchArticles(string criteria)
        {
            ArticlesServiceClient service = new ArticlesServiceClient();

            List<Article> articles = new List<Article>();
            try
            {
                articles = service.SearchArticles(criteria, WorkspaceData.Instance.RangeReview.Id);
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }


            return articles;
        }

        public void Save()
        {
            List<Article> toBeSaved = Articles.Where(art => art.GetEntityState() != EntityState.Original).ToList();

            ArticlesServiceClient service = new ArticlesServiceClient();

            try
            {
                service.SaveArticles(toBeSaved);
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }

        public void SplitArticle(Article SelectedArticle, List<Article> articles)
        {
            ArticlesServiceClient service = new ArticlesServiceClient();

            try
            {
                service.Split(SelectedArticle.Id, articles);
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }

        public void LoadArticles(int? categoryId)
        {
            ArticlesServiceClient articlesService = new ArticlesServiceClient();
            try
            {
                Articles = articlesService.GetByCategory(WorkspaceData.Instance.RangeReview.Id, categoryId, false);
                articlesService.Close();
            }
            catch
            {
                articlesService.Abort();
                throw;
            }


            //Cargo el Pareto
            if (categoryId.HasValue)
            {
                List<SalesCategoryComparisonPareto> paretoItems = null;

                ReportsService.ReportsServiceClient reportService = new ReportsService.ReportsServiceClient();
                try
                {
                    paretoItems = reportService.GetSalesCategoryComparisonPareto(WorkspaceData.Instance.RangeReview.Id, categoryId.Value);
                    reportService.Close();
                }
                catch
                {
                    reportService.Abort();
                    throw;
                }


                int count = 0;
                int totalSKUs = Articles.Where(x => !x.IsDeletedRangeReview).Count();

                if (paretoItems.Count > 0)
                {
                    decimal acumSales = 0;
                    decimal totalSales = paretoItems.Where(x => !x.IsDeletedRangeReview).Sum(x => x.Sales);
                    decimal totalSpace = paretoItems.Where(x => !x.IsDeletedRangeReview).Sum(x => x.LinearSpace);

                    if (totalSKUs != 0)
                    {
                        decimal averageLine = totalSales / totalSKUs;
                    }

                    foreach (var item in paretoItems)
                    {
                        var article = Articles.Where(x => x.Id == item.Id).FirstOrDefault();

                        if (article != null)
                        {
                            article.Sales = item.Sales;
                            article.Units = item.Units;
                            article.UnitsInCombos = item.UnitsInCombos;
                            article.Margin = item.GM;
                            article.InventoryCost = item.InventoryCost;

                            if (item.Sales != 0)
                            {
                                article.MarginP = item.GM / item.Sales;
                            }

                            if (!article.IsDeletedRangeReview)
                            {
                                if (totalSales != 0)
                                {
                                    article.PrevAcumSales = acumSales / totalSales;
                                    acumSales += item.Sales;
                                    article.AcumSales = acumSales / totalSales;
                                }

                                if (totalSKUs != 0)
                                {
                                    article.AcumSKUs = count / (decimal)totalSKUs;
                                }
                            }

                            article.Coverage = item.Coverage;
                            article.MonthsCoverage = item.MonthsCoverage;
                            article.MonthsCoverageQuantity = item.MonthsCoverageQuantity;
                            article.StoreCoverage = item.StoreCoverage;
                            article.StoreCoverageQuantity = item.StoreCoverageQuantity;
                            if (totalSales != 0)
                            {
                                article.SalesShare = article.Sales / totalSales;
                            }
                            article.TheoreticalMargin = item.TheoreticalMargin;
                            if (totalSpace > 0)
                            {
                                article.SpaceShare = item.LinearSpace / totalSpace;
                            }
                        }
                    }


                    //foreach (var item in paretoItems.Where(x => !x.IsDeletedRangeReview))
                    foreach (var article in Articles.Where(x => !x.IsDeletedRangeReview).OrderByDescending(x => x.Sales))
                    {
                        count++;
                        if (!article.IsDeletedRangeReview)
                        {
                            article.Ranking = count;
                            article.RankingSort = count;

                            //Para los articles que no tienen pareto (o sea que no tienen registros de venta)

                            if (!paretoItems.Any(x => x.Id == article.Id))
                            {
                                if (totalSales != 0)
                                {
                                    article.PrevAcumSales = acumSales / totalSales;
                                    acumSales += article.Sales;
                                    article.AcumSales = acumSales / totalSales;
                                }

                                if (totalSKUs != 0)
                                {
                                    article.AcumSKUs = count / (decimal)totalSKUs;
                                }
                            }
                        }
                    }

                    //Completo con un numero de orden los productos que están fuera del Pareto
                    foreach (var article in Articles.Where(x => x.IsDeletedRangeReview))
                    {
                        count++;
                        article.RankingSort = count;
                    }
                }

                //Cargo las ventas por fecha
                List<ARR.Entities.Gateways.SalesCategoryComparisonByDateRow> salesByDate = null;
                reportService = new ReportsService.ReportsServiceClient();
                try
                {
                    salesByDate = reportService.GetSalesCategoryComparisonByDate(WorkspaceData.Instance.RangeReview.Id, categoryId.Value);
                    reportService.Close();
                }
                catch
                {
                    reportService.Abort();
                    throw;
                }

                if (salesByDate != null && salesByDate.Count > 0)
                {
                    foreach (var item in salesByDate.Where(x => !x.IsPriorYear))
                    {
                        var article = Articles.Where(x => x.Id == item.Id).FirstOrDefault();
                        if (article != null)
                        {
                            if (article.SalesByDate == null)
                            {
                                article.SalesByDate = new Dictionary<DateTime, string>();
                            }
                            if (article.StoreCoverageQuantity > 0)
                            {
                                article.SalesByDate.Add(item.Date, item.Units.ToString("N0"));
                            }
                            else
                            {
                                article.SalesByDate.Add(item.Date, string.Empty);
                            }
                        }
                    }
                }

                //Cargo los espacios por location
                List<ARR.Entities.SalesCategoryComparisonBySpace> salesBySpace = null;
                reportService = new ReportsService.ReportsServiceClient();
                try
                {
                    salesBySpace = reportService.GetSalesCategoryComparisonBySpace(WorkspaceData.Instance.RangeReview.Id, categoryId.Value);
                    reportService.Close();
                }
                catch
                {
                    reportService.Abort();
                    throw;
                }

                if (salesBySpace != null && salesBySpace.Count > 0)
                {
                    foreach (var item in salesBySpace)
                    {
                        if (item.Location1 != null && item.LinearSpaceMts != 0)
                        {
                            var article = Articles.Where(x => x.Id == item.Id).FirstOrDefault();
                            if (article != null)
                            {
                                if (article.SpacesByLocation == null)
                                {
                                    article.SpacesByLocation = new Dictionary<string, string>();
                                    article.Planograms = item.Planograms.Trim().TrimEnd(',');
                                }

                                if (!article.SpacesByLocation.ContainsKey(item.Location1))
                                {
                                    article.SpacesByLocation.Add(item.Location1, item.LinearSpaceMts.ToString("N2"));
                                }
                                else
                                {
                                    throw new Exception(string.Format("El SKU {0} {1} tiene más de un espacio asignado para la ubicación {2}", article.Code, article.Name, item.Location1));
                                }
                            }
                        }
                    }
                }
            }
        }

        private void LoadCategories()
        {
            List<Category> categories = new List<Category>();

            CategoriesServiceClient categoryService = new CategoriesServiceClient();
            try
            {
                categories = categoryService.GetByLevels(2);
                categoryService.Close();
            }
            catch
            {
                categoryService.Abort();
                throw;
            }

            foreach (var category in categories.Where(x => x.Level == 2))
            {
                category.SubCategories = new List<Category>();
                category.SubCategories.AddRange(categories.Where(x => x.ParentId == category.Id));
            }
            Categories = categories.Where(x => x.Level == 2).OrderBy(x => x.Code).ToList();
        }

        public void LoadSubCategories(int categoryId)
        {
            CategoriesServiceClient service = new CategoriesServiceClient();

            try
            {
                SubCategories = service.GetByParentId(categoryId);
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }

        private void LoadRangeReviews()
        {
            ARR.UI.RangeReviewsService.RangeReviewsServiceClient service = new ARR.UI.RangeReviewsService.RangeReviewsServiceClient();

            try
            {
                RangeReviews = service.GetAll(WorkspaceData.Instance.Country.Id, true);
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }

        private void LoadAttributeTypes()
        {
            AttributesServiceClient service = new AttributesServiceClient();

            try
            {
                AttributeTypes = service.GetAllTypesWithValues();
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }

        private void LoadComments()
        {
            CommentsService.CommentsServiceClient service = new CommentsService.CommentsServiceClient();

            try
            {
                Comments = service.GetByType("Articles");
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }

        private void LoadUomConvertions()
        {
            UnitsOfMeasureServiceClient service = new UnitsOfMeasureServiceClient();

            try
            {
                UomConvertions = service.GetAll();
                service.Close();
            }
            catch
            {
                service.Abort();
                throw;
            }
        }
    }


    public class ArticleMasterModelMock : MockModelBase, IArticleMasterModel
    {
        public ArticleMasterModelMock()
        {
            Articles = new List<Article>();
            RangeReviews = new List<RangeReview>();
            Categories = new List<Category>();
            SubCategories = new List<Category>();
            AttributeTypes = new List<AttributeType>();
            Comments = new List<Comment>();
            UomConvertions = new List<UnitOfMeasureConvertion>();
            PlanogramLocations = new List<PlanogramLocation>();

            LoadAttributeTypes();
            LoadRangeReviews();
            LoadCategories();
            LoadArticles(null);
        }

        public List<PlanogramLocation> PlanogramLocations { get; set; }

        public List<Article> Articles { get; set; }

        public List<AttributeType> AttributeTypes { get; set; }

        public List<RangeReview> RangeReviews { get; set; }

        public List<Category> Categories { get; set; }

        public List<Category> SubCategories { get; set; }

        public List<Comment> Comments { get; set; }

        public List<UnitOfMeasureConvertion> UomConvertions { get; set; }


        public void DeleteArticles(List<Article> selectedArticles)
        {
            selectedArticles.ForEach(st =>
            {
                if (Articles.Contains(st))
                    Articles.Remove(st);
            });
        }

        public void Save()
        {

        }

        public void SplitArticle(Article SelectedArticle, List<Article> list)
        {
        }

        public void LoadArticles(int? categoryId)
        {
            Articles.Clear();

            Articles.Add(new Article { Id = 1, Code = "AR01", EAN = "AR01", Name = "Articulo 1", Category = Categories[0], CategoryId = 1, RangeReview = RangeReviews[0], RangeReviewId = 1, Brand = "Brand", Manufacturer = "Manufacturer", Attributes = new List<Entities.Attribute>() });
            Articles.Add(new Article { Id = 2, Code = "AR02", EAN = "AR02", Name = "Articulo 2", Category = Categories[0], CategoryId = 1, RangeReview = RangeReviews[0], RangeReviewId = 1, Brand = "Brand", Manufacturer = "Manufacturer", Attributes = new List<Entities.Attribute>() });
            Articles.Add(new Article { Id = 3, Code = "AR03", EAN = "AR03", Name = "Articulo 3", Category = Categories[0], CategoryId = 1, RangeReview = RangeReviews[0], RangeReviewId = 1, Brand = "Brand", Manufacturer = "Manufacturer", Attributes = new List<Entities.Attribute>() });
            Articles.Add(new Article { Id = 4, Code = "AR04", EAN = "AR04", Name = "Articulo 4", Category = Categories[0], CategoryId = 1, RangeReview = RangeReviews[0], RangeReviewId = 1, Brand = "Brand", Manufacturer = "Manufacturer", Attributes = new List<Entities.Attribute>() });
            Articles.Add(new Article { Id = 5, Code = "AR05", EAN = "AR05", Name = "Articulo 5", Category = Categories[0], CategoryId = 1, RangeReview = RangeReviews[0], RangeReviewId = 1, Brand = "Brand", Manufacturer = "Manufacturer", Attributes = new List<Entities.Attribute>() });
            Articles.Add(new Article { Id = 6, Code = "AR06", EAN = "AR06", Name = "Articulo 6", Category = Categories[0], CategoryId = 1, RangeReview = RangeReviews[0], RangeReviewId = 1, Brand = "Brand", Manufacturer = "Manufacturer", Attributes = new List<Entities.Attribute>() });
            Articles.Add(new Article { Id = 7, Code = "AR07", EAN = "AR07", Name = "Articulo 7", Category = Categories[0], CategoryId = 1, RangeReview = RangeReviews[0], RangeReviewId = 1, Brand = "Brand", Manufacturer = "Manufacturer", Attributes = new List<Entities.Attribute>() });

            //foreach (Article art in Articles)
            //{
            //    art.GetRow().ChangeState(EntityState.Original);
            //}
        }

        public List<Article> SearchArticles(string criteria)
        {
            return new List<Article>();
        }

        private void LoadCategories()
        {
            Categories.Add(new Category { Id = 1, Code = "Cat01", Name = "Categoria 1", Level = 1, Convention = "NACS" });
            Categories.Add(new Category { Id = 2, Code = "Cat02", Name = "Categoria 2", Level = 1, Convention = "NACS" });
            Categories.Add(new Category { Id = 3, Code = "Cat03", Name = "Categoria 3", Level = 1, Convention = "NACS" });
            Categories.Add(new Category { Id = 4, Code = "Cat04", Name = "Categoria 4", Level = 1, Convention = "NACS" });
            Categories.Add(new Category { Id = 5, Code = "Cat05", Name = "Categoria 5", Level = 1, Convention = "NACS" });
        }

        public void LoadSubCategories(int categoryId)
        {

        }

        private void LoadRangeReviews()
        {
            RangeReviews.Add(new RangeReview { Id = 1, CountryId = 1, FirstMonth = new DateTime(2011, 1, 1), TotalMonths = 12, Title = "Range Review 1" });
            RangeReviews.Add(new RangeReview { Id = 2, CountryId = 1, FirstMonth = new DateTime(2011, 1, 1), TotalMonths = 12, Title = "Range Review 2" });
            RangeReviews.Add(new RangeReview { Id = 3, CountryId = 1, FirstMonth = new DateTime(2011, 1, 1), TotalMonths = 12, Title = "Range Review 3" });
            RangeReviews.Add(new RangeReview { Id = 4, CountryId = 1, FirstMonth = new DateTime(2011, 1, 1), TotalMonths = 12, Title = "Range Review 4" });
        }

        private void LoadAttributeTypes()
        {
            AttributeTypes.Add(new AttributeType { Id = 1, Name = "ConsumptionType", Values = new List<Entities.Attribute>() });
            AttributeTypes.Add(new AttributeType { Id = 2, Name = "SizeSegment", Values = new List<Entities.Attribute>() });
            AttributeTypes.Add(new AttributeType { Id = 3, Name = "Flavour", Values = new List<Entities.Attribute>() });

            AttributeTypes[0].Values.Add(new Entities.Attribute { Id = 1, AttributeTypeId = 1, AttributeValue = "Immediate" });
            AttributeTypes[0].Values.Add(new Entities.Attribute { Id = 2, AttributeTypeId = 1, AttributeValue = "Future" });

            AttributeTypes[1].Values.Add(new Entities.Attribute { Id = 3, AttributeTypeId = 2, AttributeValue = "Single" });
            AttributeTypes[1].Values.Add(new Entities.Attribute { Id = 4, AttributeTypeId = 2, AttributeValue = "Multipack" });

            AttributeTypes[2].Values.Add(new Entities.Attribute { Id = 5, AttributeTypeId = 3, AttributeValue = "Apple" });
            AttributeTypes[2].Values.Add(new Entities.Attribute { Id = 6, AttributeTypeId = 3, AttributeValue = "Chocolate" });
            AttributeTypes[2].Values.Add(new Entities.Attribute { Id = 7, AttributeTypeId = 3, AttributeValue = "Almond" });
            AttributeTypes[2].Values.Add(new Entities.Attribute { Id = 8, AttributeTypeId = 3, AttributeValue = "Strawberry" });
            AttributeTypes[2].Values.Add(new Entities.Attribute { Id = 9, AttributeTypeId = 3, AttributeValue = "Honey" });
        }
    }
}
